package com.atguigu.gmall.cart.service.impl;

import com.atguigu.gmall.cart.service.CartService;
import com.atguigu.gmall.common.constant.RedisConst;
import com.atguigu.gmall.common.util.DateUtil;
import com.atguigu.gmall.model.cart.CartInfo;
import com.atguigu.gmall.model.product.SkuInfo;
import com.atguigu.gmall.product.client.ProductFeignClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author atguigu-mqx
 * @Description TODO
 * @Date 2023/7/21 15:46
 * @Version 1.0
 */
@Service
public class CartServiceImpl implements CartService {

    //  redis
    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private ProductFeignClient productFeignClient;

    @Override
    public void addToCart(Long skuId, Integer skuNum, String userId) {
        /*
        1.  判断当前购物车中是否有该商品：
               true:
                    数量相加
                    选中状态
                    修改更新时间
                    注意商品的最新价格
               false:
                    添加
         */
        //  获取购物车的key
        String cartKey = getCartKey(userId);
        //  hget key field;
        CartInfo cartInfoExist = (CartInfo) this.redisTemplate.opsForHash().get(cartKey, skuId.toString());
        //  判断是否存在该商品
        if (null != cartInfoExist){
            //  商品存在
            Integer num = cartInfoExist.getSkuNum()+skuNum>200?200:cartInfoExist.getSkuNum()+skuNum;
            cartInfoExist.setSkuNum(num);
            cartInfoExist.setSkuPrice(this.productFeignClient.getSkuPrice(skuId));

            //  从新赋值修改时间
            cartInfoExist.setUpdateTime(new Date());
            //  每次添加都是默认选中状态.
            //            if (cartInfoExist.getIsChecked().intValue()==0){
            //                cartInfoExist.setIsChecked(1);
            //            }
            cartInfoExist.setIsChecked(1);

        } else {
            //  根据skuId 获取到skuInfo
            SkuInfo skuInfo = this.productFeignClient.getSkuInfo(skuId);
            //  创建一个对象 cartInfoExist = null
            cartInfoExist = new CartInfo();
            cartInfoExist.setUserId(userId);
            cartInfoExist.setSkuId(skuId);
            cartInfoExist.setSkuNum(skuNum>200?200:skuNum);
            cartInfoExist.setSkuName(skuInfo.getSkuName());
            cartInfoExist.setImgUrl(skuInfo.getSkuDefaultImg());
            //  skuInfo.getPrice() 有几率是脏数据 -- 因为它可能从缓存中获取.
            cartInfoExist.setCartPrice(skuInfo.getPrice());
            //  实时价格：
            cartInfoExist.setSkuPrice(this.productFeignClient.getSkuPrice(skuId));
            //  设置时间
            cartInfoExist.setCreateTime(new Date());
            cartInfoExist.setUpdateTime(new Date());
        }
        //  将数据写回缓存.
        this.redisTemplate.opsForHash().put(cartKey,skuId.toString(),cartInfoExist);
        //  购物车的key 给不给过期时间啊? LRU 自动触发 删除最久的购物车数据.
    }

    @Override
    public List<CartInfo> cartList(String userTempId, String userId) {
        //  未登录购物车列表集合
        List<CartInfo> cartInfoNoLoginList = new ArrayList<>();
        //  先考虑：只有临时用户Id 或 只有用户Id 暂时不考虑都存在的情况！
        //  如果userId ，userTempId 都存在，并且未登录购物车集合有数据的情况下才能进行合并！

        //  case 1: userTempId = 111    case 2: userTempId = 111 userId = 1;
        //  !StringUtils.isEmpty(userTempId) && StringUtils.isEmpty(userId)  case 1:  return
        if (!StringUtils.isEmpty(userTempId)){
            //  获取临时购物车数据
            String cartKey = this.getCartKey(userTempId);
            //  根据key 获取到购物车集合数据 hvals key;
            cartInfoNoLoginList = this.redisTemplate.opsForHash().values(cartKey);
            //  判断当前集合是否为空。
            if (!CollectionUtils.isEmpty(cartInfoNoLoginList)){
                //  判断用户Id
                if (StringUtils.isEmpty(userId)){
                    //  只有临时购物车集合
                    cartInfoNoLoginList.sort((cartInfo1,cartInfo2)-> DateUtil.truncatedCompareTo(cartInfo2.getUpdateTime(),cartInfo1.getUpdateTime(), Calendar.SECOND));
                    //  返回未登录购物车集合列表.
                    return cartInfoNoLoginList;
                }
            }
        }

        //  用户Id 不为空。
        if (!StringUtils.isEmpty(userId)){
            //  查看登录购物车
            //  获取购物车Key
            String cartKey = this.getCartKey(userId);
            //  根据key 获取购物车对象. <H, HK, HV> hset key field value;
            BoundHashOperations<String,String,CartInfo> boundHashOperations = this.redisTemplate.boundHashOps(cartKey);
            //  hget key field = boundHashOperations.get(skuId.toString());
            //  判断临时购物车集合是否有数据. 有数据合并，没有只看登录的购物车集合。
            if (!CollectionUtils.isEmpty(cartInfoNoLoginList)){
                //  发生合并操作.
                cartInfoNoLoginList.forEach(cartInfoNoLogin -> {
                    //  判断skuId 是否相等. 17 18 19
                    if (boundHashOperations.hasKey(cartInfoNoLogin.getSkuId().toString())){
                        //  设置商品的数量
                        CartInfo cartInfoLogin = boundHashOperations.get(cartInfoNoLogin.getSkuId().toString());
                        cartInfoLogin.setSkuNum(cartInfoLogin.getSkuNum()+cartInfoNoLogin.getSkuNum()>200?200:cartInfoLogin.getSkuNum()+cartInfoNoLogin.getSkuNum());
                        //  设置一下更新时间
                        cartInfoLogin.setUpdateTime(new Date());
                        //  判断
                        if (cartInfoNoLogin.getIsChecked().intValue()==1){
                            cartInfoLogin.setIsChecked(1);
                        }
                        //  hset key field value;
                        boundHashOperations.put(cartInfoNoLogin.getSkuId().toString(),cartInfoLogin);
                    } else {
                        //    20
                        cartInfoNoLogin.setUserId(userId);
                        cartInfoNoLogin.setCreateTime(new Date());
                        cartInfoNoLogin.setUpdateTime(new Date());
                        boundHashOperations.put(cartInfoNoLogin.getSkuId().toString(),cartInfoNoLogin);
                    }
                });
                //  删除未登录购物车集合数据.
                this.redisTemplate.delete(this.getCartKey(userTempId));
            }
            //  如果未登录集合中没有数据，直接查询登录集合  临时集合没有数据，查询数据库; 合并之后的购物车集合数据
            List<CartInfo> cartInfoLoginList = boundHashOperations.values();
            //  排序
            if (CollectionUtils.isEmpty(cartInfoLoginList)){
                return new ArrayList<>();
            }
            //  排序
            //  只有临时购物车集合
            cartInfoLoginList.sort((cartInfo1,cartInfo2)-> DateUtil.truncatedCompareTo(cartInfo2.getUpdateTime(),cartInfo1.getUpdateTime(), Calendar.SECOND));
            //  返回未登录购物车集合列表.
            return cartInfoLoginList;
        }
        //  默认返回.
        return new ArrayList<>();
    }

    @Override
    public void checkCart(Long skuId, Integer isChecked, String userId) {
        //  获取购物车的key
        String cartKey = this.getCartKey(userId);
        //  先获取到购物项 hget key field;
        CartInfo cartInfo = (CartInfo) this.redisTemplate.opsForHash().get(cartKey, skuId.toString());
        if (null != cartInfo){
            cartInfo.setIsChecked(isChecked);
        }
        //  写回缓存.   hset key field value;
        this.redisTemplate.opsForHash().put(cartKey,skuId.toString(),cartInfo);
    }

    @Override
    public void allCheckCart(Integer isChecked, String userId) {
        //  获取购物车的key
        String cartKey = this.getCartKey(userId);
        //  hvals key
        List<CartInfo> cartInfoList = this.redisTemplate.opsForHash().values(cartKey);
        //        cartInfoList.forEach(cartInfo -> {
        //            //  赋值选中状态
        //            cartInfo.setIsChecked(isChecked);
        //            //  写回缓存 hset key field value;
        //            this.redisTemplate.opsForHash().put(cartKey,cartInfo.getSkuId().toString(),cartInfo);
        //        });

        //  hmset key map
        //        HashMap<String, Object> map = new HashMap<>();
        //        cartInfoList.forEach(cartInfo -> {
        //            //  赋值选中状态
        //            cartInfo.setIsChecked(isChecked);
        //            //  添加到map 集合
        //            map.put(cartInfo.getSkuId().toString(),cartInfo);
        //        });
        //        this.redisTemplate.opsForHash().putAll(cartKey,map);

        Map<String, CartInfo> map = cartInfoList.stream().map(cartInfo -> {
            cartInfo.setIsChecked(isChecked);
            return cartInfo;
        }).collect(Collectors.toMap(cartInfo -> cartInfo.getSkuId().toString(), cartInfo -> cartInfo));
        //  赋值
        this.redisTemplate.opsForHash().putAll(cartKey,map);
    }

    @Override
    public void deleteCart(Long skuId, String userId) {
        //  hdel key field;
        //  获取购物车的key
        String cartKey = this.getCartKey(userId);
        this.redisTemplate.opsForHash().delete(cartKey,skuId.toString());
    }

    @Override
    public void clearCart(String userId) {
        //  del key
        //  获取购物车的key
        String cartKey = this.getCartKey(userId);
        this.redisTemplate.delete(cartKey);
    }

    @Override
    public List<CartInfo> getCartCheckedList(String userId) {
        //  先获取到购物车的key
        String cartKey = this.getCartKey(userId);
        //  获取到选中的商品. hvals key;
        List<CartInfo> cartInfoList = this.redisTemplate.opsForHash().values(cartKey);
        //  循环遍历找出数据
        List<CartInfo> infoList = cartInfoList.stream().filter(cartInfo -> cartInfo.getIsChecked().intValue() == 1).collect(Collectors.toList());
        //  返回选中商品集合
        return infoList;
    }

    /**
     * 获取购物车的key
     * @param userId
     * @return
     */
    private String getCartKey(String userId) {
        return RedisConst.USER_KEY_PREFIX+ userId +RedisConst.USER_CART_KEY_SUFFIX;
    }

    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(1, 4, 7, 2, 5);
        list.sort((o1,o2)->{
            return o2-o1;
        });
        System.out.println(list);
    }
}
